home *** CD-ROM | disk | FTP | other *** search
- /* TTY input driver */
- #include <stdio.h>
- #include <ctype.h>
- #include "config.h"
- #include "global.h"
- #include "session.h"
-
- extern unsigned char escape; /* default escape character is ^] */
-
- #define TTY_LIT 0 /* Send next char literally */
- #define TTY_RAW 1
- #define TTY_COOKED 2
- /* TTY_ESC is escape char seen */
- #define TTY_ESC 3
-
- int ttymode = TTY_COOKED;
- int ttyecho=1;
- #define TTY_NOECHO 0
- #define TTY_ECHO 1
-
- #ifdef FLOW
- int ttyflow=1;
- #endif
-
- #define LINESIZE 256
-
- #define CTLR 18
- #define CTLU 21
- #define CTLV 22
- #define CTLW 23
- #define CTLZ 26
- #define RUBOUT 127
-
- /*
- * First, some general explanation.
- * raw and cooked are used with the usual meaning, but they don't
- * involve any change in TTY modes. Rather, the tty is set into
- * a raw mode, and cooked mode is implemented by doing our own
- * editing here. The only TTY mode we normally toggle is flow control.
- *
- * This code also handles telnet special characters. It could be
- * done in telnet, but it turns out to be easier to code it here.
- *
- * Note that raw mode is either TTY_RAW or TTY_ESC, and cooked
- * is either TTY_COOKED or TTY_LIT. TTY_ESC and TTY_LIT are special
- * substates used when a special character has been seen.
- */
-
- raw()
- {
- /*
- * TTY_ESC is part of cooked mode, so if it's set, leave it.
- */
- if (ttymode != TTY_ESC)
- ttymode = TTY_RAW;
- #ifdef ATARI_ST
- set_stdout(ttymode); /* CR/LF vs LF madness... -- hyc */
- #endif
- }
-
- cooked()
- {
- /*
- * TTY_LIT is part of cooked mode, so if it's set, leave it.
- */
- if (ttymode != TTY_LIT)
- ttymode = TTY_COOKED;
- #ifdef ATARI_ST
- set_stdout(ttymode);
- #endif
- }
-
- void
- echo()
- {
- ttyecho = TTY_ECHO;
- }
-
- void
- noecho()
- {
- ttyecho = TTY_NOECHO;
- }
-
- /*
- * Accept characters from the incoming tty buffer and process them
- * (if in cooked mode) or just pass them directly (if in raw mode).
- * Returns the number of characters available for use; if non-zero,
- * also stashes a pointer to the character(s) in the "buf" argument.
- *
- * This routine is called whenever a character is input.
- * When in cooked mode, returns zero until we've got a whole line
- * or there's some other reason to want to activate.
- *
- * This routine performs the mode switch to conversational mode.
- * If this becomes a problem, perhaps we could return a negative
- * number or some other special code.
- */
- /*Control-R added by df for retype of lines - useful in Telnet */
- /*Then df got impatient and added Control-W for erasing words */
- /* Control-V for the literal-next function, slightly improved
- * flow control, local echo stuff -- hyc */
- int
- ttydriv(c,buf)
- unsigned char c;
- unsigned char **buf;
- {
- static unsigned char linebuf[LINESIZE];
- static unsigned char *cp = linebuf;
- unsigned char *rp ;
- int cnt;
- int seenprint;
-
- if(buf == (unsigned char **)0 ) /* was this NULL for the ST ? */
- return 0; /* paranoia check */
-
- cnt = 0;
- switch(ttymode){
-
- /* TTY_LIT means we've seen a ^V in cooked mode. */
- case TTY_LIT:
- ttymode = TTY_COOKED; /* Reset to cooked mode */
- *cp++ = c;
- if(cp >= &linebuf[LINESIZE]){
- cnt = cp - linebuf;
- cp = linebuf;
- }
- break;
-
- /* TTY_ESC means we've seen the escape character in raw mode. */
- /* Raw mode is only used by telnet, so we can safely generate IAC's */
- case TTY_ESC:
- ttymode = TTY_RAW;
- if (c == escape)
- *cp++ = c;
- else switch(c & 0x1f) {
- /*BRK*/ case '\002': *cp++ = 255; *cp++ = 243; break;
- /*IP*/ case '\003': *cp++ = 255; *cp++ = 244; break;
- /*AO*/ case '\017': *cp++ = 255; *cp++ = 245; break;
- /*AYT*/ case '\024': *cp++ = 255; *cp++ = 246; break;
- /*EC*/ case '\010': *cp++ = 255; *cp++ = 247; break;
- /*EL*/ case '\025': *cp++ = 255; *cp++ = 248; break;
- case '\030': printf("\r\n"); cmdmode(); break;
- case '\037':
- printf("\r\n");
- printf("Type the escape character followed by\r\n");
- printf(" escape character - send a real escape character\r\n");
- printf(" x or ^x - return to command mode\r\n");
- printf(" b or ^b - send break\r\n");
- printf(" c or ^c - send interrupt process\r\n");
- printf(" o or ^o - abort output\r\n");
- printf(" t or ^t - are you there?\r\n");
- printf(" h or ^h - send telnet erase character\r\n");
- printf(" u or ^u - send telnet erase line\r\n");
- printf(" ? - print this help message\r\n");
- break;
- }
- cnt = cp - linebuf;
- cp = linebuf;
- break;
- case TTY_RAW:
- if (c == escape) {
- ttymode = TTY_ESC;
- break;
- }
- /*
- * More telnet-specific stuff. There's some debate
- * what to do with CR. In theory a telnet end of
- * line is CR LF, so Cisco turns CR into CR LF. But
- * experience shows that with full duplex systems
- * CR 0 (which means a real CR character) is safer.
- * Some Unix systems turn CR LF into LF. Presumably
- * on systems where CR doesn't make sense we'll be
- * in half-duplex. Our half-duplex code does use CR LF
- */
- switch(c) {
- case '\r': /* CR must be sent as CR 0 or CR LF */
- *cp++ = c;
- c = '\0';
- break;
- case 0xff: /* IAC must be doubled */
- *cp++ = c;
- break;
- }
- *cp++ = c;
- cnt = cp - linebuf;
- cp = linebuf;
- break;
- case TTY_COOKED:
- /* Perform cooked-mode line editing */
- if (mode == CONV_MODE) { /* should really check for telnet */
- if (c == escape) {
- printf("\r\n"); cmdmode(); cp = linebuf; goto endline;
- } else switch(c & 0x7f) {
- case CTLV: ttymode = TTY_LIT; goto nochar;
- /*BRK*/ case '\002': *cp++ = 255; *cp++ = 243; goto endline;
- /*IP*/ case '\003': *cp++ = 255; *cp++ = 244; goto endline;
- /*AO*/ case '\017': *cp++ = 255; *cp++ = 245; goto endline;
- /*AYT*/ case '\024': *cp++ = 255; *cp++ = 246; goto endline;
- }
- }
- #ifdef PC9801
- switch(c){
- #else
- switch(c & 0x7f){
- #endif
- case '\r': /* CR and LF are equivalent */
- case '\n':
- *cp++ = '\r';
- *cp++ = '\n';
- printf("\n");
- endline:
- cnt = cp - linebuf;
- cp = linebuf;
- nochar:
- break;
- case RUBOUT:
- case '\b': /* Backspace */
- if(cp != linebuf){
- cp--;
- if (ttyecho)
- printf("\b \b");
- }
- break;
- case CTLR: /* print line buffer */
- if(ttyecho)
- printf("^R");
- printf("\n");
- if(ttyecho) {
- rp = linebuf ;
- while (rp < cp)
- putchar(*rp++) ;
- }
- break ;
- case CTLU: /* Line kill */
- if(ttyecho) {
- while(cp != linebuf){
- cp--;
- printf("\b \b");
- }
- } else
- cp = linebuf;
- break;
- case CTLV:
- ttymode = TTY_LIT;
- break;
- case CTLW: /* erase word */
- seenprint = 0 ; /* we haven't seen a printable char yet */
- while (cp != linebuf) {
- cp--;
- if(ttyecho)
- printf("\b \b") ;
- if (isspace(*cp)) {
- if (seenprint)
- break ;
- }
- else
- seenprint = 1 ;
- }
- break ;
- default: /* Ordinary character */
- *cp++ = c;
- #ifndef AMIGA
- /* ^Z apparently hangs the terminal emulators under
- * DoubleDos and Desqview. I REALLY HATE having to patch
- * around other people's bugslike this!!!
- */
- if (ttyecho && (c != CTLZ))
- putchar(c);
- #endif
- if(cp >= &linebuf[LINESIZE]){
- cnt = cp - linebuf;
- cp = linebuf;
- }
- break;
- }
- }
- if(cnt > 0)
- *buf = linebuf;
- else
- *buf = '\0';
- /*
- * This isn't flow control in XON/XOFF sense. Rather, it's
- * a feature that holds output while the user is typing a
- * line. So if we're in the middle of a line, disable output
- */
- #ifdef FLOW
- if(cp > linebuf)
- ttyflow = 0;
- else
- ttyflow = 1;
- #endif
- fflush(stdout);
- return cnt;
- }
-